package com.brillilab.common.alioss;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.model.CopyObjectResult;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.OSSObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.exceptions.BrillilabException;

import javax.annotation.Resource;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @className: AliOssUtil
 * @description:阿里OSS对象存储服务器工具
 * @author: wuzhiyu
 * @date: 2018年10月16日 下午2:06:47
 */
@Component
public class AliOssUtil {

    private static OSSClient ossClient=null;

    @Resource
    private AliOssConfig aliOssConfig;

    /**
     * 从配置文件中读取配置信息，并初始化OSSClient。
     */
    private synchronized void init() {
        ClientConfiguration config=new ClientConfiguration();
        config.setSocketTimeout(aliOssConfig.getSocketTimeout());
        config.setConnectionTimeout(aliOssConfig.getConnectionTimeout());
        config.setMaxConnections(aliOssConfig.getMaxConnections());
        ossClient=new OSSClient(aliOssConfig.getEndPoint(),aliOssConfig.getAccessKeyId(),aliOssConfig.getAccessKeySecret(),config);
    }

    /**
     * @param file
     * @return
     * @throws BrillilabException
     * @title: saveFile
     * @description: 保存文件到alioss，并返回路径
     */
    public String saveFile(AliOssFile file) throws BrillilabException {
        if(ossClient == null){
            init();
        }

        String filePath=null;
        PutObjectResult result=null;
        Assert.isTrue(file.getFileStream() != null
                && StringUtils.isNotBlank(file.getFileName())
                && file.getFileFolder() != null
                && file.getFilePrivilege() != null,"参数缺失！");

        String path=null;
        if(OssFilePrivilegeEnum.Public.equals(file.getFilePrivilege())){
            path=file.getFilePrivilege().getValue() + (file.getFileDataId() != null ? file.getFileDataId() : "");
            result=ossClient.putObject(aliOssConfig.getPublicBucket(),file.getFilePrivilege().getValue() + (file.getFileDataId() != null ? file.getFileDataId() : "") + "/"
                    + file.getFileFolder().getValue() + "/" + file.getFileName(),file.getFileStream());
        } else if(OssFilePrivilegeEnum.Lab.equals(file.getFilePrivilege())){
            path=file.getFilePrivilege().getValue() + file.getFileDataId();
            result=ossClient.putObject(aliOssConfig.getPrivateBucket(),file.getFilePrivilege().getValue() + file.getFileDataId() + "/"
                    + file.getFileFolder().getValue() + "/" + file.getFileName(),file.getFileStream());
        } else if(OssFilePrivilegeEnum.Person.equals(file.getFilePrivilege())){
            path=file.getFilePrivilege().getValue();
            result=ossClient.putObject(aliOssConfig.getPrivateBucket(),file.getFilePrivilege().getValue() + "/"
                    + file.getFileFolder().getValue() + "/" + file.getFileName(),file.getFileStream());
        }
        if(result != null && !StringUtils.isEmpty(result.getETag())){
            if(OssFilePrivilegeEnum.Public.equals(file.getFilePrivilege())){
                filePath=getPublicHost() + path +
                        "/" + file.getFileFolder().getValue() + "/" + file.getFileName();

            } else {
                filePath=path +
                        "/" + file.getFileFolder().getValue() + "/" + file.getFileName();
            }

        } else {
            filePath=null;
        }
        return filePath;
    }

    /**
     * @throws BrillilabException
     * @Title: getThirdAppUploadPermission
     * @Description: 第三方获取alioss上传权限
     * @return: AliSts
     */
    public AliSts getThirdAppUploadPermission() throws BrillilabException {
        String stsEndpoint="sts.aliyuncs.com";
        String policy="{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // 添加endpoint（直接使用STS endpoint，前两个参数留空，无需添加region ID）
            DefaultProfile.addEndpoint("","","Sts",stsEndpoint);
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile=DefaultProfile
                    .getProfile("",aliOssConfig.getAccessKeyId(),aliOssConfig.getAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient client=new DefaultAcsClient(profile);
            final AssumeRoleRequest request=new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn("acs:ram::1526382905149969:role/labinoneapp");
            request.setRoleSessionName("appoperator");
            request.setPolicy(policy);
            //request.setPolicy(policy); // Optional
            final AssumeRoleResponse response=client.getAcsResponse(request);
            AliSts sts=new AliSts();
            sts.setAccessKeyId(response.getCredentials().getAccessKeyId());
            sts.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
            sts.setSecurityToken(response.getCredentials().getSecurityToken());
            sts.setExpireTime(response.getCredentials().getExpiration());
            return sts;
        } catch (ClientException e) {
            throw new BrillilabException(ResultEnum.FAILURE);
        }
    }

    /**
     * 删除文件
     *
     * @return
     */
    public boolean deleteFlie(String path) {
        Assert.isTrue(StringUtils.isNotBlank(path),"参数缺失！");
        String publicProffix="http://" + aliOssConfig.getPublicBucket() + "."
                + aliOssConfig.getEndPoint().replace("http://","") + "/";
        try {
            if(path.startsWith(publicProffix)){
                path=path.replace(publicProffix,"");
                ossClient.deleteObject(aliOssConfig.getPublicBucket(),path);
            } else {
                ossClient.deleteObject(aliOssConfig.getPrivateBucket(),path);
            }

        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 复制文件
     *
     * @param path
     * @return
     */
    public String copyFile(Integer fileType,Long labId,String fileName,String path){
        if(ossClient == null){
            init();
        }
        String newName=getNewFileName(fileName);
        String bucketName = getBucketByFileType(fileType);
        String sourceObjectName= getSourceObjectName(fileType,path);
        String destinationObjectName=getBasePath(fileType,labId,null)+ newName;
        String rsPath = getCopyPath(fileType,destinationObjectName);
        // 拷贝文件。
        CopyObjectResult result = ossClient.copyObject(bucketName, sourceObjectName, bucketName, destinationObjectName);
        System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
        return rsPath;
    }

    private String getSourceObjectName(Integer fileType,String path) {
        String sourceObjectName=null;
        if(OssFileFolderEnum.ExperimentFile.getKey().equals(fileType)
                && OssFileFolderEnum.NoticeFile.getKey().equals(fileType)
                && OssFileFolderEnum.EquipmentImg.getKey().equals(fileType)
                && OssFileFolderEnum.MethodFile.getKey().equals(fileType)){
            sourceObjectName = path;
        }else {
            sourceObjectName = path.replace(getPublicHost(),"");
        }
        return sourceObjectName;
    }

    private String getCopyPath(Integer fileType,String destinationObjectName) {
        String path=null;
        if(OssFileFolderEnum.ExperimentFile.getKey().equals(fileType)
                && OssFileFolderEnum.NoticeFile.getKey().equals(fileType)
                && OssFileFolderEnum.EquipmentImg.getKey().equals(fileType)
                && OssFileFolderEnum.MethodFile.getKey().equals(fileType)){
            path = getPrivateFilePath(destinationObjectName);
        }else {
            path = getPublicHost()+destinationObjectName;
        }
        return path;
    }

    private String getNewFileName(String fileName) {
        String[] nameSplit=fileName.split("\\.");
        return nameSplit[0] + "_" + new Date().getTime()  +"."+ nameSplit[1];
    }


    /**
     * 获取未加密私有文件
     *
     * @return
     */
    public OSSObject getUnencryptedPrivateObject(String path) {

        Assert.isTrue(StringUtils.isNotBlank(path),"path can not be null");

        if(ossClient == null){
            init();
        }

        //获取私有路径 过期时间1小时
        URL url=ossClient.generatePresignedUrl(aliOssConfig.getPrivateBucket(),path,
                new Date(System.currentTimeMillis() + 3600 * 1000));

        //添加GetObject请求头。
        Map<String, String> customHeaders=new HashMap<String, String>();
        customHeaders.put("Range","bytes=0-");

        //获取OSSObject
        OSSObject object=ossClient.getObject(url,customHeaders);

        Assert.notNull(object,"get OSSObject failed");

        return object;

    }

    /**
     * 获取APP文件上传基本路径
     *
     * @param fileType
     * @param labId
     * @param labMemberId
     * @return
     */
    public String getBasePath(Integer fileType,Long labId,Long labMemberId) {

        Assert.isTrue(fileType > 0 && fileType < OssFileFolderEnum.values().length,"fileType is not available");

        String basePath=null;
        switch (fileType) {
            case 1:
                basePath=OssFilePrivilegeEnum.Lab.getValue() + labId  + "/" + OssFileFolderEnum.ExperimentFile.getValue() + "/";
                break;
            case 2:
                basePath=OssFilePrivilegeEnum.Public.getValue() + labId + "/" + OssFileFolderEnum.ReagentFile.getValue() + "/";
                break;
            case 3:
                basePath=OssFilePrivilegeEnum.Lab.getValue() + labId + "/" + OssFileFolderEnum.NoticeFile.getValue() + "/";
                break;
            case 4:
                basePath=OssFilePrivilegeEnum.Lab.getValue() + labId + "/" + OssFileFolderEnum.EquipmentImg.getValue() + "/";
                break;
            case 5:
                basePath=OssFilePrivilegeEnum.Public.getValue() + labId + "/" + OssFileFolderEnum.OtherFile.getValue() + "/";
                break;
            case 6 :
                basePath=OssFilePrivilegeEnum.Lab.getValue().replaceAll("[-]$","")+ "/" + OssFileFolderEnum.MethodFile.getValue() + "/";
                break;
            default:
                break;
        }

        return basePath;
    }

    /**
     * 获取公共文件路径
     *
     * @return
     */
//    public String getPublicFilePath() {
//        return null;
//    }

    /**
     * 获取私有文件路径
     *
     * @return
     */
    public String getPrivateFilePath(String path) {
    	if(StringUtils.isNotBlank(path)) {
    		return null;
    	}
        if(ossClient == null){
            init();
        }

        //获取私有路径 过期时间1小时
        URL url=ossClient.generatePresignedUrl(aliOssConfig.getPrivateBucket(),path,
                new Date(System.currentTimeMillis() + 3600 * 1000));

        return url.toString();
    }

    /**
     * 获取私有bucket名
     *
     * @return
     */
    public String getPrivateBucket() {
        return aliOssConfig.getPrivateBucket();
    }

    /**
     * 获得公用bucket名
     *
     * @return
     */
    public String getPublicBucket() {
        return aliOssConfig.getPublicBucket();
    }

    /**
     * 通过文件类型获取bucket
     * @param fileType
     * @return
     */
    public String getBucketByFileType(Integer fileType) {

        String bucket=null;
        if(OssFileFolderEnum.ExperimentFile.getKey().equals(fileType)
                && OssFileFolderEnum.NoticeFile.getKey().equals(fileType)
                && OssFileFolderEnum.EquipmentImg.getKey().equals(fileType)
                && OssFileFolderEnum.MethodFile.getKey().equals(fileType)){
            bucket = getPrivateBucket();
        }else {
            bucket = getPublicBucket();
        }
        return bucket;
    }

    /**
     * 获取endPoint
     *
     * @return
     */
    public String getEndPoint() {
        return aliOssConfig.getEndPoint();
    }

    public String getPublicHost() {
        return "http://" + getPublicBucket() + "." +
                aliOssConfig.getEndPoint().replace("http://","") + "/";
    }

    /**
     * 获取文件缩略图URL
     * @param bucketName
     * @param fileName
     * @param style
     * @return
     */
    public URL getPresignedUrl(String bucketName, String fileName, String style) {
        if(ossClient == null){
            init();
        }
        // 设置URL过期时间 半小时
        Date expiration = new Date(new Date().getTime() + 60*1000*30 );
        // 请求处理样式后的url
        if (StringUtils.isBlank(style)){
            style = "image/resize,p_50";
        }
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, fileName, HttpMethod.GET);
        req.setExpiration(expiration);
        req.setProcess(style);
        return ossClient.generatePresignedUrl(req);
    }
}
